#include "ps_slider.h"

#include "math.h"

using namespace std;

PSSlider::PSSlider( Widget* _parent, Engine* _engine, int _x, int _y, int _w, int _h,
                    const QColor& _minColor, const QColor& _maxColor, const QColor& _ballColor )
                        :Slider( _parent, _engine, _x, _y, _w, _h, _minColor, _maxColor, _ballColor )
{    
    sliderPixmap = new QPixmap( w + 1, h + 50 );

    QColor highlightMinColor( _minColor );
    highlightMinColor.setAlpha( 255 );
    QColor highlightMaxColor( _maxColor );
    highlightMaxColor.setAlpha( 255 );

    cursorMin = 0.0;
    cursorMax = 1.0;
    showBall = true;
    showCursors = true;

    QLinearGradient highlightGradient( 0, h2, w, h2 );
    highlightGradient.setColorAt( 0, highlightMinColor );
    highlightGradient.setColorAt( 1, highlightMaxColor );

    highlightBrush = new QBrush( highlightGradient );

    QPolygonF cursorTriangle;
    cursorTriangle << QPointF( 0, h4 ) << QPointF( h4, h4 ) << QPointF( h4/2, 0 );
    cursorPath.addPolygon( cursorTriangle );

    h22 = pow( h2, 2 );
    tmpSquare = pow( h2 - 3 * h4, 2 );

    // cursor animation
    highlightAnime = new Animation( engine->fps, 400 );
    p_ni = new Power_NI< double >( 0.3 );

    minCursorProperty = new SimpleProperty< double >( "minCursor", &cursorMin );
    maxCursorProperty = new SimpleProperty< double >( "maxCursor", &cursorMax );

    i1 = new ScalarInterpolator< int, double, double >( p_ni, 0, 400, 0.0, 1.0 );
    i2 = new ScalarInterpolator< int, double, double >( p_ni, 0, 400, 0.0, 1.0 );

    i1->AttachTo( minCursorProperty );
    i2->AttachTo( maxCursorProperty );

    highlightAnime->GetTime()->AddObserver( i1 );
    highlightAnime->GetTime()->AddObserver( i2 );

    engine->AddAnimation( highlightAnime );
}

PSSlider::~PSSlider()
{
    delete highlightAnime;
    delete p_ni;
    delete i1;
    delete i2;
    delete minCursorProperty;
    delete maxCursorProperty;
    delete highlightBrush;
}

void PSSlider::Highlight( double startPos, double endPos )
{
    if( startPos > endPos ) return;
    if( startPos < 0 || startPos > 1 ) return;
    if( endPos < 0 || endPos > 1 ) return;

    i1->SetMinY( cursorMin );
    i1->SetMaxY( startPos );
    i2->SetMinY( cursorMax );
    i2->SetMaxY( endPos );

    highlightAnime->Stop();
    highlightAnime->Play();
}

void PSSlider::SetHighlightPoints( QList< double >& highlightPos )
{
    highlights = highlightPos;
}

void PSSlider::Paint( QPainter &widget_painter )
{
    sliderPixmap->fill( QColor( 0, 0, 0, 0 ) );
    QPainter painter( sliderPixmap );
    painter.setPen( Qt::black );
    painter.setBrush( *sliderBrush );
    painter.drawRoundedRect( 0, h4, w, h2, 3, 3 );

    // draws the highlight positions
    painter.setPen( Qt::gray );
    int curpos = -1;
    for( int i=0; i<highlights.size(); i++ )
    {
        if( highlights[i] == 0 || highlights[i] == 1 ) continue;
        curpos = h2 + highlights[i] * range;
        painter.drawLine( curpos, h4 + 1, curpos, h4 + h2 - 1 );
    }

    int bx = h2 + pos * range;
    int cursorMinX = h2 + cursorMin * range;
    int cursorMinY = 3 * h4;
    int cursorMaxX = h2 + cursorMax * range;
    int cursorMaxY = 3 * h4;

    // draws the highlight segment
    if( cursorMin != cursorMax )
    {
        painter.setPen( Qt::black );

        float floatWidth =  cursorMax * range - cursorMin * range;
        QRect highlightRect( h2 + cursorMin * range, h4, floatWidth, h2 );
        painter.setBrush( *highlightBrush );
        painter.drawRect( highlightRect );

        if( cursorMin == 0.0 )
        {
            painter.drawRoundedRect( 0, h4, h2 + 3, h2, 3, 3 );
            painter.setPen( Qt::NoPen );
            painter.drawRect( h2 - 4, h4 + 1, h2 + 6, h2 - 1 );
            painter.setPen( Qt::black );
        }

        if( cursorMax == 1.0 )
        {
            painter.drawRoundedRect( w - h2 - 3, h4, h2 + 3, h2, 3, 3 );
            painter.setPen( Qt::NoPen );
            painter.drawRect( w - h2 - 4, h4 + 1, 8, h2 - 1 );
            painter.setPen( Qt::black );
        }

        if( showCursors )
        {
            // if necessary, shifts the min cursor down to follow the shape of the ball
            int sq = pow( bx - cursorMinX, 2 );
            int d2 = sq + tmpSquare;
            if( d2 < h22 )
            {
                cursorMinY = sqrt( h22 - sq ) + h2;
            }

            // ..the same thing for the max cursor
            sq = pow( bx - cursorMaxX, 2 );
            d2 = sq + tmpSquare;
            if( d2 < h22 )
            {
                cursorMaxY = sqrt( h22 - sq ) + h2;
            }

            // finally draws the cursors
            painter.translate( cursorMinX - h4/2, cursorMinY );
            painter.drawPath( cursorPath );
            painter.drawText( h4/2 - 2, h4 + 10, "S" );
            painter.translate( -cursorMinX + h4/2, -cursorMinY);

            painter.translate( cursorMaxX - h4/2, cursorMaxY );
            painter.drawPath( cursorPath );
            painter.drawText( h4/2 - 2, h4 + 10, "E" );
            painter.translate( -cursorMaxX + h4/2, -cursorMaxY );
        }
    }

    // draws the ball
    if( showBall )
    {
        painter.setBrush( *sliderBrush );
        painter.setPen( Qt::black );
        QPoint ballCenter( bx, h2 );
        QRect outerBallRect( bx - h2, 0, h, h );
        innerBallRect->setRect( bx - ballRadius, h2 - ballRadius, 2 * ballRadius, 2 * ballRadius );

        painter.setPen( Qt::NoPen );
        painter.drawEllipse( ballCenter, h2, h2 );

        painter.setPen( Qt::black );
        painter.drawArc( outerBallRect, 30 * 16, 120 * 16 );
        painter.drawArc( outerBallRect, -30 * 16, -120 * 16 );

        QRadialGradient* gradient = ( QRadialGradient* )ballBrush->gradient();
        gradient->setRadius( ballGradientRadius );
        gradient->setCenter( bx, h2 );
        gradient->setFocalPoint( bx, h2 );
        painter.setBrush( *ballBrush );
        painter.drawEllipse( QPoint( bx, h2 ), ballRadius, ballRadius );
    }

    painter.end();

    if( showWidth > 1 )
    {
        widget_painter.drawPixmap( x, y, *sliderPixmap, 0, 0, showWidth + 1, h + 50 );
    }
}
